// class constructors do not return anything


inline
kmeans::kmeans(const mat &in_data, const uword in_Ncent)
: data(in_data), N_cent(in_Ncent), Dim(in_data.n_rows), N_data(data.n_cols)
{
}

inline
void
kmeans::run(const uword max_iter)
{
  //cout << "Dim = " << Dim << endl;
  uword iter = 0;
  ini_cent();// Initializing cent_1
  
  //mat saveCent=cent_1.t();
  //saveCent.save("C_ini.dat", raw_ascii);
  do
  {
    update_cent(); //means are updated inside this method
    cout << iter << ".. ";
    
    if (iter < max_iter)
    {
      err;      
    }
    else
    {
      err = 0;
      distortion = 0;  // -- Nov15,2013 
    }
    
    cout << "- Err= " << err << " & distortion= " << distortion << endl; // -- Nov15,2013 
    iter++;
  }while ( (err !=0 )  );
  cout << endl;

  
}


inline
void 
kmeans::ini_cent()
{
  //cout << "...Doing init_cent";
  uvec initial_indices;
  vec tmp = randu<vec>(N_cent) * (data.n_cols-1); 
  initial_indices = conv_to<uvec>::from( tmp );// converting to <uvec> from <vec>
  cent_1.zeros(Dim, N_cent);
  
  for(uword ci=0; ci < N_cent; ++ci)
  {
    cent_1.col(ci) = data.col( initial_indices(ci));
    //Descomentar
    //cout << "Initial Centroid corresponds to: " << initial_indices(ci) << " is " << labels_actions(initial_indices(ci),0) << endl;
  }
  
  
}

inline
void 
kmeans::update_cent()
{
  
  //cout << "...doing update cent" ;
  partitions.zeros(N_data,N_cent);
  distances.zeros(N_cent);
  cent_2.zeros(Dim, N_cent);
  counts.zeros(N_cent);
  distortion = 0;// Nov15,2013
  Points_cent.zeros(N_data, N_cent); // Nov15,2013
  
    
  
  for(uword ni = 0; ni < N_data; ++ni)
  {
    for(uword ci = 0; ci < N_cent; ++ci)
    {
      distances(ci) = norm( (data.col(ni) - cent_1.col(ci)), 2 );
    }
    double mind = distances.min(best_ci);
    distortion+=mind;
    partitions(counts(best_ci),best_ci)=ni;
    Points_cent(counts(best_ci),best_ci)= mind;
    counts(best_ci) += 1;
  }
  
  for (uword ci=0; ci<N_cent; ++ci)
  {
    uword out=counts(ci);
    for (uword j=0; j<out ; ++j)
    {
      cent_2.col(ci)+=data.col(partitions(j,ci));
    }
    
    if (counts(ci)==0)
    {
      cent_2.col(ci).fill(0);   
    }
    else
    {
      cent_2.col(ci) /= double( counts(ci) );
    } 
    
  }
  
  double change = accu( abs( cent_1 - cent_2 ) );
  err = change;
  cent_1 = cent_2;
  means = cent_1;
}


inline
void
kmeans::print_labels(const field<std::string>  labels)
{
  //partitions.print("Final Partitions");
  field<std::string> lab_partitions( N_data , N_cent );
  // uvec q1 = find (tmp2 == c);
  
  for (uword ci = 0; ci < N_cent; ++ci)  
  {
    uvec v = partitions.col(ci);
    //v.print("v: ");
    v.resize(counts(ci));
    //v.print("v: ");
    //labels(v).fill(ci);
    cout << "Cluster " << ci + 1 << " has  " << counts(ci) << " points" << endl;
    for (uword n = 0; n< counts(ci); ++n)
    {
      //labels(v(n),0) = lab(ci,0);
      cout <<  labels( partitions( n,ci ),0 ) << endl;
      lab_partitions( n , ci ) = labels( partitions( n,ci ) ); 
      // getchar();
    }
    cout << endl ;
    
    //getchar();*/
  }
  //lab_partitions.print("Final labels: ");
  
}

inline
uvec
kmeans::get_id_summ()
{
  uvec indices = sort_index(counts);
  uvec indices_summary;
  
  indices_summary.zeros(N_data);
  
  //partitions.print("Partitions");
  indices.t().print("sorted indices:");
  
  
  double length_summ = floor(N_data*30/100);
  uword j =0;
  uword ne;
  uword pos;
  
  for (uword i = 0; i < counts.n_elem ; ++i)
  {
    pos = indices(i);
    ne = counts( pos ) - 1;
    indices_summary.subvec ( j, j + ne) = partitions(  span(0, ne ) , pos);
    cout << "j= "<< j << " - next j: " << j + ne + 1 << endl;
    j = j + ne + 1;
    uvec tmp = partitions(  span(0, ne ), pos);
    //tmp.t().print("Current indices ");
    //cout << "Current indices " << partitions(  span(0, ne , pos)) << endl;
    //j = j + ne + 1;
    getchar();
    
  }
  
  
  //cout << "p_sum " <<   p_sum << endl;
  indices_summary.resize(length_summ);
  
  //indices_summary.t().print("indices_summary");
  return sort( indices_summary ); // returning only the smaller clusters 
}


inline
uvec
kmeans::near_points() // Check it! I implement but I haven't checked
{
  //To select the closest point to the centrioid.
  uvec point_cluster(counts.n_elem);   //Closest point per cluster
  
  vec dist_ci;
  uword  index;
  //double min_val;
  cout << "i= ";
  int add=0;
  for (uword i = 0; i < counts.n_elem ; ++i)
  {
    if (counts(i)>0)
    {
    cout << i << " ";
    dist_ci.zeros(counts(i));
    dist_ci = Points_cent( span(0, counts(i) - 1) , i );
    dist_ci.min(index);
    point_cluster (add) = partitions(index,i);
    add++;
    }
    
  }
  cout << "add" << add << endl;
  point_cluster.resize(add);
  
  return sort(point_cluster);
}




inline
umat
kmeans::get_partitions()
{
  //partitions.print("partitions");
  return partitions;
  
}

